﻿using RpcCentral.Collect;
using RpcCentral.Collect.Collect;
using RpcCentral.Collect.Controller;
using RpcCentral.Collect.Model;
using RpcCentral.Common;
using RpcCentral.Model;
using RpcCentral.Service.Interface;
using RpcHelper;
using RpcModel;

namespace RpcCentral.Service.Service
{
    internal class GetServiceListService : IGetServiceListService
    {
        private ISystemTypeCollect _SystemType;
        private IRpcServerConfigCollect _ServerConfig;
        private IVerConfigCollect _VerConfig;
        private ITransmitConfigCollect _TransmitConfig;
        public GetServiceListService(ISystemTypeCollect systemType,
            IRpcServerConfigCollect serverConfig,
            IVerConfigCollect verConfig,
            ITransmitConfigCollect transmitConfig)
        {
            this._SystemType = systemType;
            this._ServerConfig = serverConfig;
            this._VerConfig = verConfig;
            this._TransmitConfig = transmitConfig;
        }

        public GetServerListRes GetServerList(GetServerList obj, Source source)
        {
            SystemTypeDatum type = this._SystemType.GetSystemType(obj.SystemType);
            RpcServerConfigController config = this._ServerConfig.Get(obj.RpcMerId, type.Id);
            RpcVerController verConfig = _VerConfig.GetVer(obj.RpcMerId, type.Id, source.ApiVer);
            if (obj.LimitRegionId.HasValue)
            {
                int tVer = obj.TransmitVer;
                int ver = obj.Ver;
                ServerConfig[] services = this._GetServers(config, obj.LimitRegionId.Value, ref ver, ref tVer);
                return new GetServerListRes
                {
                    BalancedType = type.BalancedType,
                    TransmitVer = tVer,
                    Ver = ver,
                    Servers = verConfig.Filters(type.Id, services)
                };
            }
            else
            {
                int ver = obj.Ver;
                int tVer = obj.TransmitVer;
                ServerConfig[] locals = this._GetServers(config, source.RegionId, ref ver, ref tVer, out ServerConfig[] backs);
                return new GetServerListRes
                {
                    BalancedType = type.BalancedType,
                    TransmitVer = tVer,
                    Ver = ver,
                    Servers = verConfig.Filters(type.Id, locals),
                    BackUp = verConfig.Filters(type.Id, backs)
                };
            }

        }
        private ServerConfig[] _GetServers(RpcServerConfigController config, int regionId, ref int ver, ref int tVer, out ServerConfig[] back)
        {
            TransmitConfigController transmit = this._TransmitConfig.GetTransmit(config.SystemTypeId, config.RpcMerId);
            if (!transmit.CheckVer(ref ver) && ver == config.Ver)
            {
                back = null;
                return null;
            }
            else
            {
                ver = config.Ver;
                if (!config.IsRegionIsolate)
                {
                    back = null;
                    return config.Server.ConvertMap<RpcServiceConfig, ServerConfig>((a, b) =>
                    {
                        transmit.InitConfig(b);
                        return b;
                    });
                }
                else if (config.IsolateLevel)
                {
                    back = null;
                    return config.Server.ConvertMap<RpcServiceConfig, ServerConfig>(a => a.RegionId == regionId, (a, b) =>
                    {
                        transmit.InitConfig(b);
                        return b;
                    });
                }
                else
                {
                    ServerConfig[] locals = config.Server.ConvertMap<RpcServiceConfig, ServerConfig>(a => a.RegionId == regionId, (a, b) =>
                    {
                        transmit.InitConfig(b);
                        return b;
                    });
                    if (locals.Length == 0)
                    {
                        back = null;
                        return config.Server.ConvertMap<RpcServiceConfig, ServerConfig>((a, b) =>
                        {
                            transmit.InitConfig(b);
                            return b;
                        });
                    }
                    back = config.Server.ConvertMap<RpcServiceConfig, ServerConfig>(a => a.RegionId != regionId, (a, b) =>
                    {
                        transmit.InitConfig(b);
                        return b;
                    });
                    return locals;
                }
            }
        }

        private ServerConfig[] _GetServers(RpcServerConfigController config, int regionId, ref int ver, ref int tVer)
        {
            TransmitConfigController transmit = this._TransmitConfig.GetTransmit(config.SystemTypeId, config.RpcMerId);
            if (!transmit.CheckVer(ref tVer) && ver == config.Ver)
            {
                return null;
            }
            else
            {
                ver = config.Ver;
                return config.Server.ConvertMap<RpcServiceConfig, ServerConfig>(a => a.RegionId == regionId, (a, b) =>
                {
                    transmit.InitConfig(b);
                    return b;
                });
            }
        }
    }
}
